//package com.zjmzxfzhl.common.aspect;
//
//import java.lang.reflect.InvocationTargetException;
//import java.util.concurrent.TimeUnit;
//
//import org.apache.commons.beanutils.PropertyUtils;
//import org.aspectj.lang.ProceedingJoinPoint;
//import org.aspectj.lang.annotation.Around;
//import org.aspectj.lang.annotation.Aspect;
//import org.aspectj.lang.annotation.Pointcut;
//import org.aspectj.lang.reflect.MethodSignature;
//import org.redisson.api.RLock;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.core.annotation.Order;
//import org.springframework.stereotype.Component;
//import org.springframework.web.context.request.RequestAttributes;
//import org.springframework.web.context.request.RequestContextHolder;
//
//import com.zjmzxfzhl.common.aspect.annotation.RepeatRequest;
//import com.zjmzxfzhl.common.exception.BaseException;
//import com.zjmzxfzhl.common.redlock.RedissonDistributedLocker;
//import com.zjmzxfzhl.common.util.ShiroUtils;
//import com.zjmzxfzhl.modules.app.common.AppSessionObject;
//import com.zjmzxfzhl.modules.app.interceptor.AppLoginInterceptor;
//
//import lombok.extern.slf4j.Slf4j;
//
///**
// * 登录用户请求防重发处理,Order=0优先于RedissonLockAspect
// *
// * @author 庄金明
// * @date 2020年3月24日
// */
//@Aspect
//@Component
//@Order(0)
//@Slf4j
//public class RepeatRequestAspect {
//	@Autowired
//	private RedissonDistributedLocker redissonDistributedLocker;
//
//	// 管理端请求，若有多个modules则使用||运算符增加拦截controller方法，如下
//	// @Pointcut("execution(* com.*..*.sys.controller.*.*(..)) || execution(* com.*..*.othermodule.controller.*.*(..))")
//	// 或者使用拦截全部controller，然后排除个别非管理端的controller，如下
//	// @Pointcut("execution(* com.*..*.controller.*.*(..)) && !execution(* com.*..*.app.controller.*.*(..))")
//	/**
//	 * 后台管理请求切面
//	 */
//	@Pointcut("execution(* com.*..*.sys.controller.*.*(..)) || execution(* com.*..*.demo.controller.*.*(..)) || execution(* com.*..*.flowable.controller.*.*(..))")
//	private void controllerAspect() {
//	}
//
//	/**
//	 * APP端请求切面
//	 */
//	@Pointcut("execution(* com.*..*.app.controller.*.*(..))")
//	private void controllerAspectForApp() {
//	}
//
//	@Around("controllerAspect()")
//	public Object controllerAspectAround(ProceedingJoinPoint joinPoint) throws Throwable {
//		String userId = ShiroUtils.getUserId();
//		if (userId == null || userId.length() == 0) {
//			userId = "";
//		}
//		return exec(joinPoint, userId);
//	}
//
//	@Around("controllerAspectForApp()")
//	public Object controllerAspectForAppAround(ProceedingJoinPoint joinPoint) throws Throwable {
//		AppSessionObject appSessionObject = (AppSessionObject) RequestContextHolder.getRequestAttributes()
//				.getAttribute(AppLoginInterceptor.APP_SESSION_OBJECT, RequestAttributes.SCOPE_REQUEST);
//		String userId = "";
//		if (appSessionObject != null && appSessionObject.getUserId() != null && appSessionObject.getUserId().length() != 0) {
//			userId = appSessionObject.getUserId();
//		}
//		return exec(joinPoint, userId);
//	}
//
//	/**
//	 * 执行登录用户交易防重发
//	 *
//	 * @param joinPoint
//	 * @param userId
//	 * @return
//	 * @throws IllegalAccessException
//	 * @throws InvocationTargetException
//	 * @throws NoSuchMethodException
//	 * @throws Throwable
//	 */
//	private Object exec(ProceedingJoinPoint joinPoint, String userId)
//			throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, Throwable {
//		// 默认不等待、且30秒后释放锁
//		int waitTime = 0, leaseTime = 30;
//		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//		RepeatRequest repeatRequest = signature.getMethod().getAnnotation((RepeatRequest.class));
//		// 未设置注解，且未登录
//		if (repeatRequest == null && userId.length() == 0) {
//			return joinPoint.proceed();
//		}
//		String lockParams = "";
//		// 如果controller包含该注解，则解析注解并封装参数lockParams
//		if (repeatRequest != null) {
//			// 设置注解带过来的等待时间
//			waitTime = repeatRequest.waitTime();
//			// 设置注解带过来的释放时间
//			leaseTime = repeatRequest.leaseTime();
//			/**
//			 * repeatRequest.isExistAndOnlyUserId()
//			 *
//			 * true时，若用户未登陆，则只使用 lockIndexs 组拼key，若用户已登录，只使用 userId 组拼 key 忽略 lockIndexs
//			 *
//			 * false时，若用户未登陆，则只使用 lockIndexs 组拼key，若用户已登录，即使用 userId 组拼 key 也使用 lockIndexs 组拼key
//			 */
//			if (!repeatRequest.isExistAndOnlyUserId() || userId.length() == 0) {
//				Object[] params = joinPoint.getArgs();
//				int[] lockIndexs = repeatRequest.lockIndexs();
//				String[] fieldNames = repeatRequest.fieldNames();
//				// 锁2个及2个以上参数时，fieldNames数量应与lockIndexs一致
//				if (fieldNames.length > 1 && lockIndexs.length != fieldNames.length) {
//					throw new BaseException("lockIndexs与fieldNames数量不一致");
//				}
//				if (lockIndexs.length > 0) {
//					StringBuffer lockParamsBuffer = new StringBuffer();
//					for (int i = 0; i < lockIndexs.length; i++) {
//						if (fieldNames.length == 0 || fieldNames[i] == null || fieldNames[i].length() == 0) {
//							lockParamsBuffer.append("." + params[lockIndexs[i]]);
//						} else {
//							Object lockParamValue = PropertyUtils.getSimpleProperty(params[lockIndexs[i]], fieldNames[i]);
//							lockParamsBuffer.append("." + lockParamValue);
//						}
//					}
//					lockParams = lockParamsBuffer.toString();
//				}
//			}
//		}
//
//		// 防止锁整个方法
//		if (userId.length() == 0 && lockParams.length() == 0) {
//			return joinPoint.proceed();
//		}
//
//		Object obj = null;
//		// 取得锁的key
//		StringBuffer keyBuffer = new StringBuffer();
//		keyBuffer.append(signature.getDeclaringTypeName()).append(".").append(signature.getName());
//		if (userId.length() != 0) {
//			keyBuffer.append(".").append(userId);
//		}
//		if (lockParams.length() != 0) {
//			keyBuffer.append(lockParams);
//		}
//		String key = keyBuffer.toString();
//		RLock rlock = redissonDistributedLocker.getLock(key);
//		boolean isSuccess = redissonDistributedLocker.tryLock(rlock, waitTime, leaseTime, TimeUnit.SECONDS);
//		if (isSuccess) {
//			log.info("取到锁[" + key + "]");
//			try {
//				obj = joinPoint.proceed();
//			} finally {
//				log.info("释放锁[" + key + "]");
//				redissonDistributedLocker.unlock(rlock);
//			}
//		} else {
//			throw new BaseException(repeatRequest == null ? "交易未执行完毕，请勿重复提交" : repeatRequest.msg());
//		}
//		return obj;
//	}
//}
